home *** CD-ROM | disk | FTP | other *** search
/ Aminet 23 / Aminet 23 (1998)(GTI - Schatztruhe)[!][Feb 1998].iso / Aminet / util / misc / TeeHandler.lha / TeeHandler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-12-18  |  13.9 KB  |  526 lines

  1. /* 
  2. ** $VER: TeeHandler.c 1.40 (17th December 1997) 
  3. */
  4. #include <exec/types.h>
  5. #include <exec/tasks.h>
  6. #include <exec/ports.h>
  7. #include <exec/memory.h>
  8. #include <dos/dos.h>
  9. #include <dos/dosextens.h>
  10. #include <dos/filehandler.h>
  11. #include <clib/exec_protos.h>
  12. #include <clib/dos_protos.h>
  13.  
  14.  
  15. /* Program Information */
  16. #define PROG_NAME  "tee-handler"
  17. #define PROG_VER   "1"
  18. #define PROG_REV   "40"
  19. #define PROG_DATE  "17th December 1997"
  20.  
  21. /* Version String */
  22. const char VerStr[] = "\0$VER: "PROG_NAME" "PROG_VER"."PROG_REV" ("PROG_DATE")\r\n";
  23.  
  24.  
  25. #ifdef DEBUG
  26.  
  27. /* Prototypes for debug.lib functions */
  28. extern __stkargs void kputs(STRPTR string);
  29. extern __stkargs void kprintf(STRPTR format, ... );
  30.  
  31.  
  32. /* Strings associated with actions known by this handler */
  33. STRPTR Actions[] = {"ACTION_FINDUPDATE",
  34.                     "ACTION_FINDOUTPUT",
  35.                     "ACTION_SEEK",
  36.                     "ACTION_WRITE",
  37.                     "ACTION_END",
  38.                     "ACTION_IS_FILESYSTEM"};
  39.  
  40. /*
  41. ** KPrint a string indicating packet type.
  42. */
  43. __regargs void KPutPacketName(LONG Type)
  44. {
  45.   int i;
  46.   
  47.   switch (Type) {
  48.     case ACTION_FINDUPDATE:     i = 1; break;
  49.     case ACTION_FINDOUTPUT:     i = 2; break;
  50.     case ACTION_SEEK:           i = 3; break;
  51.     case ACTION_WRITE:          i = 4; break;
  52.     case ACTION_END:            i = 5; break;
  53.     case ACTION_IS_FILESYSTEM:  i = 6; break;
  54.     default:                    i = 0;
  55.   }
  56.   if (i) kprintf("TeeHandler: Got an %s packet.\n\n",Actions[i-1]);
  57.   else   kprintf("TeeHandler: Got an Unknown packet (%ld).\n\n",Type);
  58. }
  59.  
  60. #endif
  61.  
  62.  
  63. /*
  64. ** Convert a BString to a CString.
  65. ** String must be duplicated if you wish to keep it.
  66. */
  67. __regargs STRPTR b2cstr(BSTR bstring)
  68. {
  69. #ifdef DEBUG
  70.   kputs  ("            TeeHandler: b2cstr() Called:\n");
  71.   kprintf("                        BString = \"%b\"\n",bstring);
  72. #endif
  73.  
  74.   static char cstring[255];
  75.   STRPTR realbstr;
  76.   UBYTE len;
  77.   int i;
  78.   
  79.   realbstr = (STRPTR)BADDR(bstring);
  80.   len = realbstr[0];
  81.   
  82.   for (i=0; i<len; i++)
  83.     cstring[i] = realbstr[i+1];
  84.   cstring[i] = '\0';
  85.   
  86. #ifdef DEBUG
  87.   kprintf("                        CString = \"%s\"\n",cstring);
  88.   kputs  ("            TeeHandler: b2cstr() Finished.\n\n");
  89. #endif
  90.  
  91.   return cstring;
  92. }
  93.  
  94. /*
  95. ** Get a pointer to the Process that sent the packet.
  96. */
  97. #define FindPktProc(pkt) \
  98.          ((struct Process *)((UBYTE *)(pkt)->dp_Port - sizeof(struct Task)))
  99.  
  100.  
  101. struct TeeArgs {
  102.   ULONG  ArgC;
  103.   STRPTR *ArgV;
  104. };
  105.  
  106. /*
  107. ** Parse a given Argument String into C-style ArgC/ArgV.
  108. ** Format of TeeHandler Arguments:
  109. **    <DOSDEV>:<Arg1>,<Arg2>,...,<ArgN>   ;   "\," ==> ","
  110. */
  111. __regargs struct TeeArgs *ParseArgs(STRPTR ArgS)
  112. {
  113. #ifdef DEBUG
  114.   kputs  ("            TeeHandler: ParseArgs() Called.\n");
  115. #endif
  116.  
  117.   struct TeeArgs *teeArgs;
  118.   STRPTR *ArgV;
  119.   STRPTR Strings;
  120.   ULONG ArgC;
  121.   ULONG CharC;
  122.   int i,j,k,l;
  123.   
  124.   
  125.   /* Count the number of Arguments and Characters */
  126.   
  127.   /* First for DOSDEV: ... */
  128.   for (i=0; ArgS[i] != ':'; i++)
  129.     ;
  130.   i++;
  131.   ArgC = 1;
  132.   CharC = i;
  133.   
  134.   /* Then for the rest of the Arguments */
  135.   for (j=i; ArgS[j] != '\0'; j++)
  136.   {
  137.     if (ArgS[j] == ',')
  138.       ArgC++;
  139.     else if (ArgS[j] == '\\')
  140.       j++;
  141.     
  142.     CharC++;
  143.   }
  144.   ArgC++;
  145.   
  146.   /* Add two NULL byte for DeviceName: and last argument (no commas) */
  147.   CharC += 2;
  148.   
  149.   /* Allocate memory for ArgC string pointers   */
  150.   /*  = sizeof(teeArgs) + ArgC*4 + CharC        */
  151.   teeArgs = (struct TeeArgs *)
  152.             AllocVec(sizeof(struct TeeArgs) + (ArgC<<2) + CharC, NULL);
  153.   if (!teeArgs)
  154.     /* Oh dear, no memory ... Shall we try it with individual   */
  155.     /* allocations?  Why bother?  CRASH AND BURN, HA HA HA HA!! */
  156.     return NULL;
  157.   
  158.   /* So a map of our memory block would be:  */
  159.   /*   struct TeeArgs {                      */
  160.   /*     ULONG   ArgC;                       */
  161.   /*     STRPTR *ArgV;                       */
  162.   /*   };                                    */
  163.   /*   STRPTR ArgV[ArgC];                    */
  164.   /*   "DeviceName:",0                       */
  165.   /*   "Arg1",0                              */
  166.   /*   "Arg2",0                              */
  167.   /*     ...                                 */
  168.   /*   "ArgN",0    (where N == ArgC-1)       */
  169.   
  170.   /* Link it all together ... */
  171.   teeArgs->ArgC = ArgC;
  172.   ArgV = (STRPTR *)((UBYTE *)teeArgs + sizeof(struct TeeArgs));
  173.   teeArgs->ArgV = ArgV;
  174.   Strings = (STRPTR)((UBYTE *)ArgV + (ArgC<<2));
  175.   ArgV[0] = Strings;
  176.   
  177.   /*  i indicates the current position in the ArgS string          */
  178.   /*  j incicates the current position in the Strings memory block */
  179.   /*  k indicates the current argument                             */
  180.   /*  l indicates the start of the current argument                */
  181.   
  182.   /* Copy device name */
  183.   for (i=0, j=0; ArgS[i] != ':'; i++, j++)
  184.     Strings[j] = ArgS[i];
  185.   Strings[j++] = ':'; i++;
  186.   Strings[j++] = '\0';
  187.   
  188.   /* Copy arguments */
  189.   for (k=1,l=j; ArgS[i] != '\0'; i++,j++)
  190.   {
  191.     if (ArgS[i] == ',')
  192.     {
  193.       Strings[j] = '\0';
  194.       
  195.       ArgV[k++] = Strings+l;
  196.       l = j+1;
  197.     }
  198.     else if (ArgS[i] == '\\')
  199.       Strings[j] = ArgS[++i];
  200.     else
  201.       Strings[j] = ArgS[i];
  202.   }
  203.   Strings[j] = '\0';
  204.   ArgV[k] = Strings+l;
  205.   
  206.   /* Well, that should do it... */
  207. #ifdef DEBUG
  208.   kputs  ("            TeeHandler: ParseArgs() Finished.\n\n");
  209. #endif
  210.   return teeArgs;
  211. }
  212.  
  213.  
  214. /*
  215. ** Delete the entire TeeArgs structure and associated fields.
  216. */
  217. __regargs void DeleteArgs(struct TeeArgs *teeArgs)
  218. {
  219. #ifdef DEBUG
  220.   kputs  ("            TeeHandler: DeleteArgs() Called.\n");
  221. #endif
  222.  
  223.   /* Because this was allocated in one big block, */
  224.   /* we can release it all with just one call     */
  225.   FreeVec((APTR)teeArgs);
  226.  
  227. #ifdef DEBUG
  228.   kputs  ("            TeeHandler: DeleteArgs() Finished.\n\n");
  229. #endif
  230. }
  231.  
  232.  
  233. /*
  234. ** Perform WaitPkt() with a port other than pr_MsgPort.
  235. */
  236. __regargs struct DosPacket *WaitPktPort(struct MsgPort *port)
  237. {
  238.   struct Message *msg;
  239.  
  240.   WaitPort(port);
  241.   msg = GetMsg(port);
  242.   return (struct DosPacket *)msg->mn_Node.ln_Name;
  243. }
  244.  
  245. /*
  246. ** Perform ReplyPkt() with a port other then pr_MsgPort.
  247. */
  248. __regargs void ReplyPktPort(struct MsgPort *port, 
  249.                             struct DosPacket *dp, LONG Res1, LONG Res2)
  250. {
  251.   struct MsgPort *rport = dp->dp_Port;
  252.   
  253.   dp->dp_Res1 = Res1;
  254.   dp->dp_Res2 = Res2;
  255.   dp->dp_Port = port;
  256.   
  257.   PutMsg(rport,dp->dp_Link);
  258. }
  259.  
  260.  
  261. struct DOSLibrary *DOSBase;
  262.  
  263. /*
  264. ** Entry Point
  265. */
  266. __stkargs int _main(int len, char *args)
  267. {
  268.   struct TeeArgs *teeArgs;
  269.   ULONG  ArgC;
  270.   STRPTR *ArgV;
  271.   BPTR   *OutputFiles;    /* [0] = StdOutFile, [1..n] = OutputFiles */
  272.   
  273.   struct DosPacket *packet;
  274.   struct MsgPort *teePort;
  275.   struct DeviceNode *teeDevNode;
  276.   struct Process *teeProc;
  277.   struct Process *callProc;
  278.   struct FileHandle *teeFileHandle;
  279.   
  280.   ULONG  running = TRUE;
  281.   ULONG  opencnt = 0;
  282.   LONG   rc = DOSTRUE, rc2 = 0;
  283.   int i;
  284.   
  285.   
  286. #ifdef DEBUG
  287.   kputs  ("TeeHandler Started.\n\n");
  288. #endif
  289.   
  290.   /* Get this process and attempt to open DOS Library v36+ */
  291.   teeProc = (struct Process *)FindTask(NULL);
  292.   DOSBase = (struct DOSLibrary *)OpenLibrary("dos.library",36);
  293.   if (!DOSBase)
  294.     /* Maybe an alert here to inform the good user that s/he's using */
  295.     /* an obsolete operating system?                                 */
  296.     return RETURN_FAIL;
  297.   
  298.   /* Wait for the startup packet */
  299. #ifdef DEBUG
  300.   kputs("TeeHandler: Waiting for startup packet...\n\n");
  301. #endif
  302.   packet = WaitPktPort(&teeProc->pr_MsgPort);
  303.   
  304.   /* Got the startup packet, now initialise it and reply */
  305.   /*  dp_Arg1 ==> (BSTR) Mount Name (ie Mount TEE:)      */
  306.   /*  dp_Arg3 ==> (BPTR) Device Node                     */
  307.   
  308.   /* Create a new MsgPort so we don't confuse the dos.library */
  309.   teePort = CreateMsgPort();
  310.   if (!teePort)
  311.   {
  312.     /* No memory? No signal? */
  313.     CloseLibrary((struct Library *)DOSBase);
  314.     rc = FALSE;
  315.     rc2 = ERROR_OBJECT_NOT_FOUND;
  316.   }
  317.   
  318.   teeDevNode = (struct DeviceNode *)BADDR(packet->dp_Arg3);
  319.   teeDevNode->dn_Task = teePort;
  320.   ReplyPktPort(teePort,packet,rc,rc2);
  321.   if (rc2)
  322.     return RETURN_FAIL;
  323.   
  324.   /* Main Loop */
  325. #ifdef DEBUG
  326.   kputs("TeeHandler: Starting Main Loop\n");
  327. #endif
  328.   while (running)
  329.   {
  330.     /* Wait for an action packet */
  331. #ifdef DEBUG
  332.     kputs("TeeHandler: Waiting for action packet...\n");
  333. #endif
  334.     packet = WaitPktPort(teePort);
  335. #ifdef DEBUG
  336.     KPutPacketName(packet->dp_Type);
  337. #endif
  338.  
  339.     /* Got an action packet. */
  340.     switch (packet->dp_Type)
  341.     {
  342.     /*******************************************************************/
  343.     
  344.     case ACTION_FINDUPDATE:
  345.     case ACTION_FINDOUTPUT:
  346.       /* Setup for output (eg Open("TEE:",MODE_OLDFILE))   */
  347.       /*  dp_Arg1 = (BPTR) File Handle                     */
  348.       /*  dp_Arg3 = (BSTR) Access Name (eg Dir >TEE:T:bla) */
  349.       
  350.       opencnt++;                          /* We have another user! */
  351.       
  352. #ifdef DEBUG
  353.       kprintf("            Argument String = \"%b\"\n\n",packet->dp_Arg3);
  354. #endif
  355.       teeArgs = ParseArgs(b2cstr((BSTR)packet->dp_Arg3));
  356.       if (!teeArgs)
  357.       {
  358.         /* Aww, no memory */
  359.         if (!(--opencnt)) running = FALSE;
  360.         rc = FALSE;
  361.         rc2 = ERROR_NO_FREE_STORE;
  362.         
  363.         break;
  364.       }
  365.       ArgC = teeArgs->ArgC;
  366.       ArgV = teeArgs->ArgV;
  367.       
  368.       /* Now Allocate some memory for the Output Files Array */
  369.       /*  = ArgC + 2 (StdOut and -1 End Marker)              */
  370.       OutputFiles = (BPTR *)AllocVec( (ArgC+2)<<2 ,MEMF_CLEAR);
  371.       if (!OutputFiles)
  372.       {
  373.         /* No Memory! */
  374.         DeleteArgs(teeArgs);
  375.         if (!(--opencnt)) running = FALSE;
  376.         rc = FALSE;
  377.         rc2 = ERROR_NO_FREE_STORE;
  378.         
  379.         break;
  380.       }
  381.       
  382.       /* Save the caller's Output and change to it's CurrentDir */
  383.       callProc = FindPktProc(packet);
  384.       OutputFiles[0] = callProc->pr_COS;
  385.       CurrentDir(callProc->pr_CurrentDir);
  386. #ifdef DEBUG
  387.       struct CommandLineInterface *CLI = (struct CommandLineInterface *)
  388.                                           BADDR(callProc->pr_CLI);
  389.  
  390.       kprintf("            Calling Process: 0x%08lx\n",callProc);
  391.       kprintf("            Task Name:       %s\n",callProc->pr_Task.tc_Node.ln_Name);
  392.       if (CLI)
  393.         kprintf("            CommandName:     %b\n",CLI->cli_CommandName);
  394.       kprintf("            Output Stream:   0x%08lx\n\n",OutputFiles[0]);
  395. #endif
  396.       
  397.       /* Open each of our Output files */
  398.       for (i=1; i < ArgC; i++)
  399.       {
  400. #ifdef DEBUG
  401.         kprintf("            OutputName = \"%s\"\n",ArgV[i]);
  402. #endif
  403.         if (ArgV[i][0] != '\0')
  404.           OutputFiles[i] = Open(ArgV[i],packet->dp_Type);
  405.         
  406. #ifdef DEBUG
  407.         kprintf("            OutputFile Handle = 0x%08lx\n\n",OutputFiles[i]);
  408. #endif
  409.       }
  410.       /* Set the last field to -1 */
  411.       OutputFiles[ArgC] = -1;
  412.       
  413.       /* Set the file handle's relevent items */
  414.       teeFileHandle = (struct FileHandle *)BADDR(packet->dp_Arg1);
  415.       teeFileHandle->fh_Port = (struct MsgPort *)DOSTRUE;
  416.       teeFileHandle->fh_Args = (LONG)teeFileHandle;
  417.       teeFileHandle->fh_Arg2 = (LONG)OutputFiles;
  418.       
  419.       /* Get rid of the Arguments */
  420.       DeleteArgs(teeArgs);
  421.       
  422.       break;
  423.     
  424.     /*******************************************************************/
  425.     
  426.     case ACTION_SEEK:
  427.       /* Perform Seek Action (eg Seek(TeeFile, Position, Offset))      */
  428.       /*  dp_Arg1 = File Handle's fh_Args (set by ACTION_FIND... )     */
  429.       /*  dp_Arg2 = (LONG) Position to move to, based on offset.       */
  430.       /*  dp_Arg3 = (LONG) Offset: Start or End of file or current pos */
  431.       
  432. #ifdef DEBUG
  433.       int t = packet->dp_Arg3;
  434.       
  435.       kprintf("            Offset Position: %s+(%ld).\n\n",
  436.                                  (t ? (t < 0 ? "Start" : "End") : "Current"),
  437.                                  packet->dp_Arg2);
  438. #endif
  439.       
  440.       teeFileHandle = (struct FileHandle *)packet->dp_Arg1;
  441.       OutputFiles = (BPTR *)teeFileHandle->fh_Arg2;
  442.       
  443.       for (i=1; OutputFiles[i] != -1; i++)
  444.         if (OutputFiles[i])
  445.           Seek(OutputFiles[i],packet->dp_Arg2,packet->dp_Arg3);
  446.       
  447.       break;
  448.     
  449.     /*******************************************************************/
  450.     
  451.     case ACTION_WRITE:
  452.       /* Perform write actions (eg Write(TeeFile, buffer, bufsize)) */
  453.       /*  dp_Arg1 = File Handle's fh_Args (set by ACTION_FIND... )  */
  454.       /*  dp_Arg2 = (APTR) Pointer to buffer to write               */
  455.       /*  dp_Arg3 = (ULONG) Number of bytes to write                */
  456.       
  457. #ifdef DEBUG
  458.       kprintf("            Writing %ld bytes.\n\n",packet->dp_Arg3);
  459. #endif
  460.       
  461.       teeFileHandle = (struct FileHandle *)packet->dp_Arg1;
  462.       OutputFiles = (BPTR *)teeFileHandle->fh_Arg2;
  463.       rc = packet->dp_Arg3;
  464.       
  465.       for (i=0; OutputFiles[i] != -1; i++)
  466.         if (OutputFiles[i])
  467.           Write(OutputFiles[i],(APTR)packet->dp_Arg2,rc);
  468.       
  469.       break;
  470.     
  471.     /*******************************************************************/
  472.     
  473.     case ACTION_END:
  474.       /* Reverse actions taken by ACTION_FIND* ...                  */
  475.       /*  dp_Arg1 = File Handle's fh_Args (set by ACTION_FIND... )  */
  476.       
  477.       teeFileHandle = (struct FileHandle *)packet->dp_Arg1;
  478.       OutputFiles = (BPTR *)teeFileHandle->fh_Arg2;
  479.       
  480.       for (i=1; OutputFiles[i] != -1; i++)
  481.         if (OutputFiles[i])
  482.           Close(OutputFiles[i]);
  483.       
  484.       FreeVec((APTR)OutputFiles);
  485.       
  486.       if (!(--opencnt)) running = FALSE;
  487.       break;
  488.     
  489.     /*******************************************************************/
  490.     
  491.     case ACTION_IS_FILESYSTEM:
  492.       /* Is this a FileSystem?  Erm ... Nope.  Sorry. */
  493.       
  494.       rc = FALSE;
  495.       /* rc2 = 0 */
  496.       
  497.       break;
  498.     
  499.     /*******************************************************************/
  500.     
  501.     default:
  502.       /* All other packets dock here */
  503.       
  504.       rc = FALSE;
  505.       rc2 = ERROR_ACTION_NOT_KNOWN;
  506.       
  507.       /* break; */
  508.     
  509.     /*******************************************************************/
  510.     }
  511.     
  512.     /* Reply back to the calling Process */
  513.     ReplyPktPort(teePort,packet,rc,rc2);
  514.   }
  515.   
  516.   /* Now we close up and exit */
  517. #ifdef DEBUG
  518.   kputs("TeeHandler Shutting Down.\n\n\n");
  519. #endif
  520.   teeDevNode->dn_Task = NULL;
  521.   DeleteMsgPort(teePort);
  522.   CloseLibrary((struct Library *)DOSBase);
  523.   
  524.   return RETURN_OK;
  525. }
  526.